#include "ImGui/ImGuiAPI.h"

#include "Core/GlobalContext.h"

#include <backends/imgui_impl_glfw.h>
#include <backends/imgui_impl_opengl3.h>
#include <GLFW/glfw3.h>

namespace SE
{
	ImGuiAPI::ImGuiAPI()
	{
		SE_PROFILE_FUNCTION();

		auto currentWindowContext = GlobalContext::GetWindowContext();
		SE_ASSERT(currentWindowContext, "No current window context!");

		// Setup Dear ImGui context
		IMGUI_CHECKVERSION();
		ImGui::CreateContext();
		ImGuiIO& io = ImGui::GetIO(); (void)io;
		io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
		io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
		io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;         // Enable Docking
		io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;       // Enable Multi-Viewport / Platform Windows
		//io.ConfigViewportsNoAutoMerge = true;
		//io.ConfigViewportsNoTaskBarIcon = true;

		// Setup Dear ImGui style
		ImGui::StyleColorsDark();
		//StyleColorsLight();

		// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
		ImGuiStyle& style = ImGui::GetStyle();
		if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
		{
			style.WindowRounding = 0.0f;
			style.Colors[ImGuiCol_WindowBg].w = 1.0f;
		}

		// Setup Platform/Renderer backends
		ImGui_ImplGlfw_InitForOpenGL((GLFWwindow*)(currentWindowContext->nativeWindow), true);
		ImGui_ImplOpenGL3_Init("#version 450");
	}

	ImGuiAPI::~ImGuiAPI()
	{
		SE_PROFILE_FUNCTION();

		// Cleanup
		ImGui_ImplOpenGL3_Shutdown();
		ImGui_ImplGlfw_Shutdown();
		ImGui::DestroyContext();
	}

	Ref<ImGuiContext> ImGuiAPI::CreateContext()
	{
		return CreateRef<ImGuiContext>();
	}

	void ImGuiAPI::DestoryContext(const Ref<ImGuiContext>& context)
	{
	}

	Ref<ImGuiAPI> ImGuiAPI::Create()
	{
		if (RenderAPIType::OpenGL == RenderAPI::GetAPIType() || WindowAPIType::GLFW == WindowAPI::GetAPIType())
		{
			return CreateRef<ImGuiAPI>();
		}
		SE_ASSERT(false, "No support to these api types!");
		return nullptr;
	}

	void ImGuiAPI::MakeContextCurrent(const Ref<ImGuiContext>& context)
	{
		SE_ASSERT(context, "Empty context!");

		GlobalContext::GetImGuiAPI()->mCurrentContext = context;
	}

	void ImGuiAPI::RenderBegin()
	{
		SE_PROFILE_FUNCTION();

		// Start the Dear ImGui frame
		ImGui_ImplOpenGL3_NewFrame();
		ImGui_ImplGlfw_NewFrame();
		ImGui::NewFrame();
	}

	void ImGuiAPI::RenderEnd()
	{
		SE_PROFILE_FUNCTION();

		// Rendering
		ImGui::Render();
		I32 display_w = 0, display_h = 0;
		auto currentWindowContext = GlobalContext::GetWindowContext();
		SE_ASSERT(currentWindowContext, "No current window context!");
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

		// Update and Render additional Platform Windows
		// (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
		//  For this specific demo app we could also call glfwMakeContextCurrent(window) directly)
		ImGuiIO& io = ImGui::GetIO(); (void)io;
		if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
		{
			ImGui::UpdatePlatformWindows();
			ImGui::RenderPlatformWindowsDefault();
			glfwMakeContextCurrent((GLFWwindow*)(currentWindowContext->nativeWindow));
		}
	}
} // !namespace SE